package com.xxc.exam.service.impl

import com.xxc.batis.service.MysqlCrudServiceImpl
import com.xxc.exam.entity.CategoryEntity
import com.xxc.exam.entity.pojo.Category
import com.xxc.exam.entity.pojo.Manager
import com.xxc.exam.entity.vo.CategoryVO
import com.xxc.exam.mapper.CategoryMapper
import com.xxc.exam.service.CategoryService
import org.springframework.beans.BeanUtils
import org.springframework.stereotype.Service
import org.springframework.util.Assert
import tk.mybatis.mapper.entity.Example
import java.lang.StringBuilder
import java.math.BigInteger

@Service
class CategoryServiceImpl : MysqlCrudServiceImpl<Category,CategoryMapper>(),CategoryService {
    override fun getParents(id: BigInteger): CategoryEntity {
        return getParentsCircle(id)
    }

    private fun getParentsCircle(id:BigInteger): CategoryEntity {
        val origin = wrapCategoryEntity(crudMapper.selectByPrimaryKey(id))
        if(origin.parent != null && origin.parent!!.id != null)
        {
            origin.parent = getParentsCircle(origin.parent!!.id!!)
        }
        return origin
    }

    override fun getFullPathName(id: BigInteger): String? {
        val origin = getParents(id)
        val builder = StringBuilder()
        createFullPathName(origin,builder)
        return builder.deleteCharAt(builder.length-1).toString()
    }

    private fun createFullPathName(categoryEntity: CategoryEntity,builder: StringBuilder)
    {
        if(categoryEntity.parent != null && categoryEntity.parent!!.id != null)
            createFullPathName(categoryEntity.parent!!,builder)
        builder.append(categoryEntity.name).append("/")
    }

    override fun selectAllEntities(ownerId: BigInteger): List<CategoryVO> {
       return select(ownerId)
    }

    private fun select(ownerId: BigInteger,pid:BigInteger? = null):MutableList<CategoryVO>{
        val example = Example(Category::class.java)
        val criteria = example.createCriteria()
        if(pid == null)
            criteria.andIsNull("pid")
        else
            criteria.andEqualTo("pid",pid)
        criteria.andEqualTo("ownerId",ownerId)
        val secondCategory = crudMapper.selectByExample(example)
        val vos = ArrayList<CategoryVO>(secondCategory.size)
        for (category in secondCategory) {
            val vo = wrapCategoryVO(category)
            vos.add(vo)
            val children = select(ownerId, category.id)
            if(children.isNotEmpty())
            {
                vo.children = children
            }
        }
        return vos
    }


    private fun wrapCategoryEntity(category: Category): CategoryEntity {
        val entity = CategoryEntity()
        BeanUtils.copyProperties(category,entity)
        if(category.pid != null)
        {
            entity.parent = CategoryEntity(id = category.pid)
        }
        return entity
    }

    private fun wrapCategoryVO(category: Category):CategoryVO
    {
        val vo = CategoryVO()
        BeanUtils.copyProperties(category,vo)
        return vo
    }



    override fun insertCategory(category: CategoryEntity,ownerId:BigInteger) {
        Assert.notNull(category.name,"category' name can't be null")
        val root = insertIfNotExist(wrapCategory(category,ownerId))
        category.id = root.id
        //如果子元素不为空则插入子元素
        if(category.children != null)
            insertChildren(category,ownerId)
    }

    private fun insertChildren(c: CategoryEntity,ownerId: BigInteger){
        Assert.notNull(c.id,"category' id can't be null")
        Assert.notNull(c.name,"category' name can't be null")
        for(cate in c.children!!){
            var wrapCategory = wrapCategory(cate, ownerId)
            wrapCategory.pid = c.id
            cate.id = insertIfNotExist(wrapCategory).id
            //如果有子类则循环插入子元素
            if(cate.children != null)
            {
                insertChildren(cate,ownerId)
            }
        }
    }

    private fun wrapCategory(category: CategoryEntity,ownerId: BigInteger):Category{
        return Category(name = category.name,ownerId = ownerId)
    }

    override fun insertIfNotExist(category: Category): Category {
        Assert.notNull(category.ownerId,"owerId can't be null")
        Assert.isTrue(!category.name.isNullOrBlank(),"name can't be empty or null")
        val selected = crudMapper.selectOne(category) as Category?
        if(selected != null)
            return selected
        else
        {
            this.insert(category)
            return category
        }
    }

    override fun select(category: Category): List<CategoryVO> {
        return crudMapper.select(category).map {
            CategoryVO(it.id, it.name)
        }
    }


}